package jfupdater.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedList;
import java.util.List;

import jfupdater.ui.R;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.xml.sax.InputSource;

import android.util.Log;
import android.widget.Toast;

public class PlainTextUpdateServer implements IUpdateServer {
	
	private static final String TAG = "PlainTextUpdateServer";
	//private static final URI UPDATE_FILE_URI = URI.create("http://10.0.2.2:8080/update.txt");
	private static final URI UPDATE_FILE_URI = URI.create("http://android-dls.com/up.txt");
	
	private HttpClient httpClient;
	
	public PlainTextUpdateServer() {
		httpClient = new DefaultHttpClient();
	}

	@Override
	public void downloadUpdateFile(UpdateInfo ui, File destinationFile)
			throws IOException {
		HttpUriRequest req;
		HttpResponse response;
		for(URI updateURI:ui.updateFileUris) {
			req = new HttpGet(updateURI);
			response = httpClient.execute(req);
			int serverResponse = response.getStatusLine().getStatusCode();
			if(serverResponse != 200) {
				Log.e(TAG, "Server returned status code " + serverResponse + " trying next mirror");
			}
			dumpFile(response.getEntity(), destinationFile);
			return;
		}
		
		Log.e(TAG, "Unable to download the update file from any mirror");
		throw new IOException("Unable to download the update");
	}

	private void dumpFile(HttpEntity entity, File destinationFile) throws IOException {
		byte[] buff = new byte[64 * 1024];
		int read;
		FileOutputStream fos = new FileOutputStream(destinationFile);
		InputStream is = entity.getContent();
		try {
			while( (read = is.read(buff)) > 0) {
				fos.write(buff, 0, read);
			}
			fos.flush();
		} finally {
			entity.consumeContent();
			fos.close();
		}
	}

	@Override
	public List<UpdateInfo> getAvailableUpdates() throws IOException {
		
		HttpUriRequest req = new HttpGet(UPDATE_FILE_URI);
		HttpResponse response = httpClient.execute(req);
		
		int serverResponse = response.getStatusLine().getStatusCode();
		if(serverResponse != 200) {
			Log.e(TAG, "Server returned status code " + serverResponse);
			throw new IOException("Server returned status code " + serverResponse);
		}
		
		LinkedList<UpdateInfo> retValue = new LinkedList<UpdateInfo>();
		HttpEntity responseEntity = response.getEntity();
		String line;
		UpdateInfo ui;
		try {
			BufferedReader lineReader = new BufferedReader(
									new InputStreamReader(responseEntity.getContent()));
			
			while((line = lineReader.readLine()) != null) {
				if(line.trim().charAt(0) == '#') continue;

				ui = parseLine(line);
				if(ui != null) retValue.add(ui);
			}

			lineReader.close();
		} finally {
			responseEntity.consumeContent();
		}
		
		return retValue;
	}

	private UpdateInfo parseLine(String line) {
		//mod|versionCode|displayVersion|displayName|md5sum|mirror1|mirror2|mirror3|mirror4|etc
		UpdateInfo ui = new UpdateInfo();
		String[] p = line.split("\\|");
		
		if(p.length < 5) {
			Log.w(TAG, "Unable to parse update line. Found " + p.length + " parameters, expected >=5");
			return null;
		}
		
		ui.mod = p[0];
		try {
			ui.versionCode = Integer.parseInt(p[1]);
		} catch (NumberFormatException ex) {
			Log.w(TAG, "Unable to parse versionCode string (" + p[1] + "). Ignoring this update", ex);
			return null;
		}
		ui.displayVersion = p[2];
		ui.displayName = p[3];
		ui.md5 = p[4];
		ui.updateFileUris = new LinkedList<URI>();
		for(int i = 5; i < p.length; i++) {
			try {
				ui.updateFileUris.add(new URI(p[i]));
			} catch (URISyntaxException e) {
				Log.w(TAG, "Unable to parse mirror url (" + p[i] + "). Ignoring this mirror", e);
			}
		}
		
		if(ui.updateFileUris.size() == 0) {
			Log.w(TAG, "No mirrors found, ignoring this update");
			return null;
		}
		
		return ui;
	}

}
